#ifndef __BASE_RefObj_h__
#define __BASE_RefObj_h__

#include <string.h>
#include <stdint.h>

#define GCC_VERSION (__GNUC__ * 10000           \
                     + __GNUC_MINOR__ * 100		\
                     + __GNUC_PATCHLEVEL__)

#if GCC_VERSION > 40200 
#include <ext/atomicity.h>
#else
#include <bits/atomicity.h>
#endif
namespace BASE{
    inline void atomic_add(volatile int* val, int count) {
        __gnu_cxx::__atomic_add(val, count);
    }

    
    class RefObj
    {
    private:
        volatile int  mRefCount;
        static  volatile int  sAllCount;
        
    public:
        RefObj(): mRefCount(0){
        }

        virtual ~RefObj() {
        }
        
        static int getAllCount() {
            return sAllCount;
        }

        virtual int addRef();
        virtual bool release();
    
        int refCount() { return mRefCount; }
    };
   
    template <typename T>
    class RefPtrBase {
    public:
        T* p;
    protected:
        RefPtrBase(){
            p = NULL;
        }
        RefPtrBase(int nNull){
            p = NULL;
        }
        RefPtrBase(T* lp) {
            p = lp;
            if (p != NULL)
                p->addRef();
        }

    public:
        typedef T _PtrClass;
        ~RefPtrBase() {
            if (p)
                p->release();
        }
        operator T*() const {
            return p;
        }
        T& operator*() {
            return *p;
        }
        T* operator->() const {
            return (T*)p;
        }

        bool operator!() const {
            return (p == NULL);
        }

        bool operator<(T* pT) const {
            return p < pT;
        }

        bool operator!=(T* pT) const {
            return !operator==(pT);
        }

        bool operator==(T* pT) const {
            return p == pT;
        }

        void release() {
            T* pTemp = p;
            if (pTemp) {
                p = NULL;
                pTemp->release();
            }
        }

        void attach(T* p2) {
            if (p)
                p->release();
            p = p2;
        }

        T* detach() {
            T* pt = p;
            p = NULL;
            return pt;
        }
    };

    template <class T>
    class RefPtr : public RefPtrBase<T>  {
    public:
        RefPtr() {
        }
        RefPtr(int nNull):
            RefPtrBase<T>(nNull) {
        }

        RefPtr(T* lp) :
            RefPtrBase<T>(lp) {
        }
      
        RefPtr(const RefPtr<T>& lp) : 
            RefPtrBase<T>(lp.p) {
        }

        template<class M>
        RefPtr(const RefPtr<M>& lp) :
            RefPtrBase<T>(dynamic_cast<T*>(lp.p)) {
        }
      
        T* operator=( T* lp) {
            if(*this != lp)  {
                if (RefPtrBase<T>::p) {
                    RefPtrBase<T>::p->release();
                }

                RefPtrBase<T>::p = lp;
                if (RefPtrBase<T>::p) {
                    RefPtrBase<T>::p->addRef();
                }
            }
            return RefPtrBase<T>::p;
        }

        T* operator=(const RefPtr<T>& lp)    {
            if(*this != lp)  {
                if (RefPtrBase<T>::p) {
                    RefPtrBase<T>::p->release();
                }

                RefPtrBase<T>::p = lp.p;

                if (RefPtrBase<T>::p) {
                    RefPtrBase<T>::p->addRef();
                }
            }
            return RefPtrBase<T>::p;
        }

        template <typename _AS> 
        _AS* cast() {
            return dynamic_cast<_AS*>(RefPtrBase<T>::p);
        }
    };
    
    typedef RefPtr<RefObj> RefObjPtr;
}
#endif //__libshms_RefObj_h__
